/*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "magtheridons_lair.h"
#include "SpellInfo.h"

enum Yells
{
    SAY_TAUNT						= 0,
    SAY_FREE						= 1,
    SAY_AGGRO						= 2,
    SAY_SLAY						= 3,
    SAY_BANISH						= 4,
    SAY_PHASE3						= 5,
    SAY_DEATH						= 6,
};

enum Emotes
{
	SAY_EMOTE_BEGIN					= 7,
	SAY_EMOTE_NEARLY				= 8,
	SAY_EMOTE_FREE					= 9,
	SAY_EMOTE_NOVA					= 10
};

enum Spells
{
    SPELL_SHADOW_CAGE			= 30205,
    SPELL_BLAST_NOVA			= 30616,
    SPELL_CLEAVE				= 30619,
    SPELL_BLAZE					= 30541,
	SPELL_BLAZE_SUMMON			= 30542,
    SPELL_BERSERK				= 27680,
    SPELL_SHADOW_GRASP_VISUAL	= 30166,
    SPELL_MIND_EXHAUSTION		= 44032,
    SPELL_QUAKE					= 30657,
    SPELL_COLLAPSE_DAMAGE		= 36449,
    SPELL_CAMERA_SHAKE			= 36455,
    SPELL_DEBRIS_VISUAL			= 30632,
    SPELL_DEBRIS_DAMAGE			= 30631
};

enum Events
{
	EVENT_EMOTE1				= 1,
	EVENT_EMOTE2				= 2,
	EVENT_EMOTE3				= 3,
	EVENT_ENTER_COMBAT			= 4,
	EVENT_RECENTLY_SPOKEN		= 5,

	EVENT_CLEAVE				= 10,
	EVENT_BLAST_NOVA			= 11,
	EVENT_BLAZE					= 12,
	EVENT_ENRAGE				= 13,
	EVENT_QUAKE					= 14,
	EVENT_CHECK_HEALTH			= 15,
	EVENT_COLLAPSE_CEIL			= 16,
	EVENT_COLLAPSE_DAMAGE		= 17,
	EVENT_DEBRIS				= 18,

	EVENT_RANDOM_TAUNT			= 30,
	EVENT_CHECK_GRASP			= 31,
	EVENT_CANCEL_GRASP_CHECK	= 32
};

class DealDebrisDamage : public BasicEvent
{
public:
	DealDebrisDamage(Creature& creature, uint64 targetGUID) : _owner(creature), _targetGUID(targetGUID) { }

	bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/)
	{
		if (Unit* target = ObjectAccessor::GetUnit(_owner, _targetGUID))
			target->CastSpell(target, SPELL_DEBRIS_DAMAGE, true, NULL, NULL, _owner.GetGUID());
		return true;
	}

private:
	uint64 _targetGUID;
	Creature& _owner;
};

class boss_magtheridon : public CreatureScript
{
    public:

        boss_magtheridon() : CreatureScript("boss_magtheridon") { }

        struct boss_magtheridonAI : public BossAI
        {
            boss_magtheridonAI(Creature* creature) : BossAI(creature, TYPE_MAGTHERIDON) { }

			EventMap events2;
 

            void Reset()
            {
				events2.Reset();
				events2.ScheduleEvent(EVENT_RANDOM_TAUNT, 90000);
				_Reset();
                me->CastSpell(me, SPELL_SHADOW_CAGE, true);
				me->SetReactState(REACT_PASSIVE);
				me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_IMMUNE_TO_PC);
            }

            void KilledUnit(Unit* victim)
            {
				if (events.GetNextEventTime(EVENT_RECENTLY_SPOKEN) == 0)
				{
					events.ScheduleEvent(EVENT_RECENTLY_SPOKEN, 5000);
					Talk(SAY_SLAY);
				}
            }

            void JustDied(Unit* /*killer*/)
            {
                _JustDied();
                Talk(SAY_DEATH);
            }

            void MoveInLineOfSight(Unit* /*who*/) { }

            void EnterCombat(Unit* /*who*/)
            {
				events2.Reset();
                _EnterCombat();
				events.ScheduleEvent(EVENT_EMOTE1, 0);
				events.ScheduleEvent(EVENT_EMOTE2, 60000);
				events.ScheduleEvent(EVENT_EMOTE3, 120000);
				events.ScheduleEvent(EVENT_ENTER_COMBAT, 123000);

           }

            void UpdateAI(uint32 diff)
            {
				events2.Update(diff);
				switch (events2.ExecuteEvent())
				{
					case EVENT_RANDOM_TAUNT:
						Talk(SAY_TAUNT);
						events2.ScheduleEvent(EVENT_RANDOM_TAUNT, 90000);
						break;
					case EVENT_CHECK_GRASP:
						if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
						{
							Talk(SAY_BANISH);
							me->InterruptNonMeleeSpells(true);
							break;
						}
						events2.ScheduleEvent(EVENT_CHECK_GRASP, 0);
						break;
				}


                if (!UpdateVictim() || !CheckInRoom())
                    return;

				events.Update(diff);
				if (me->HasUnitState(UNIT_STATE_CASTING))
					return;

				switch (events.ExecuteEvent())
				{
					case EVENT_EMOTE1:
						Talk(SAY_EMOTE_BEGIN);
						break;
					case EVENT_EMOTE2:
						Talk(SAY_EMOTE_NEARLY);
						break;
					case EVENT_EMOTE3:
						Talk(SAY_EMOTE_FREE);
						Talk(SAY_FREE);
						break;
					case EVENT_ENTER_COMBAT:
						me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_IMMUNE_TO_PC);
						me->SetReactState(REACT_AGGRESSIVE);
						events.ScheduleEvent(EVENT_CLEAVE, 9000);
						events.ScheduleEvent(EVENT_BLAST_NOVA, 60000);
						events.ScheduleEvent(EVENT_BLAZE, 10000);
						events.ScheduleEvent(EVENT_QUAKE, 40000);
						events.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
						events.ScheduleEvent(EVENT_ENRAGE, 22*MINUTE*IN_MILLISECONDS);

						instance->SetData(DATA_ACTIVATE_CUBES, 1);
						me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE);
						break;
					case EVENT_CLEAVE:
						me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
						events.ScheduleEvent(EVENT_CLEAVE, 10000);
						break;
					case EVENT_BLAST_NOVA:
						me->CastSpell(me, SPELL_BLAST_NOVA, false);
						events.ScheduleEvent(EVENT_BLAST_NOVA, 60000);
						events.ScheduleEvent(EVENT_CANCEL_GRASP_CHECK, 12000);
						events2.ScheduleEvent(EVENT_CHECK_GRASP, 0);
						break;
					case EVENT_BLAZE:
						me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1);
						events.ScheduleEvent(EVENT_BLAZE, 30000);
						break;
					case EVENT_ENRAGE:
						me->CastSpell(me, SPELL_BERSERK, true);
						break;
					case EVENT_CANCEL_GRASP_CHECK:
						events2.Reset();
						break;
					case EVENT_QUAKE:
						me->CastSpell(me, SPELL_QUAKE, false);
						events.ScheduleEvent(EVENT_QUAKE, 50000);
						break;
					case EVENT_CHECK_HEALTH:
						if (me->HealthBelowPct(30))
						{
							Talk(SAY_PHASE3);
							events.SetPhase(1);
							events.DelayEvents(18000);
							events.ScheduleEvent(EVENT_COLLAPSE_CEIL, 8000);
							events.ScheduleEvent(EVENT_COLLAPSE_DAMAGE, 15000);
							break;
						}
						events.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
						break;
					case EVENT_COLLAPSE_CEIL:
						me->CastSpell(me, SPELL_CAMERA_SHAKE, true);
						instance->SetData(DATA_COLLAPSE, GO_STATE_ACTIVE);
						break;
					case EVENT_COLLAPSE_DAMAGE:
						me->CastSpell(me, SPELL_COLLAPSE_DAMAGE, true);
						me->resetAttackTimer();
						events.SetPhase(0);
						events.ScheduleEvent(EVENT_DEBRIS, 20000);
						break;
					case EVENT_DEBRIS:
						if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
						{
							target->CastSpell(target, SPELL_DEBRIS_VISUAL, true, NULL, NULL, me->GetGUID());
							me->m_Events.AddEvent(new DealDebrisDamage(*me, target->GetGUID()), me->m_Events.CalculateTime(5000));
						}
						events.ScheduleEvent(EVENT_DEBRIS, 20000);
						break;
				}

				if (!events.IsInPhase(1))
					DoMeleeAttackIfReady();
            }
        };

        CreatureAI* GetAI(Creature* creature) const
        {
            return GetInstanceAI<boss_magtheridonAI>(creature);
        }
};

class spell_magtheridon_blaze : public SpellScriptLoader
{
    public:
        spell_magtheridon_blaze() : SpellScriptLoader("spell_magtheridon_blaze") { }

        class spell_magtheridon_blaze_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_magtheridon_blaze_SpellScript);

            void HandleScriptEffect(SpellEffIndex /*effIndex*/)
            {
                if (Unit* target = GetHitUnit())
                    target->CastSpell(target, SPELL_BLAZE_SUMMON, true);
            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_magtheridon_blaze_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_magtheridon_blaze_SpellScript();
        }
};

class spell_magtheridon_shadow_grasp : public SpellScriptLoader
{
public:
    spell_magtheridon_shadow_grasp() : SpellScriptLoader("spell_magtheridon_shadow_grasp") { }

    class spell_magtheridon_shadow_grasp_AuraScript : public AuraScript
    {
        PrepareAuraScript(spell_magtheridon_shadow_grasp_AuraScript)
        
		void HandleDummyApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
        {
			GetUnitOwner()->CastSpell((Unit*)NULL, SPELL_SHADOW_GRASP_VISUAL, false);
        }
		
		void HandleDummyRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
        {
			GetUnitOwner()->InterruptNonMeleeSpells(true);
        }

		void HandlePeriodicRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
        {
			GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_MIND_EXHAUSTION, true);
        }

        void Register()
        {
			OnEffectApply += AuraEffectApplyFn(spell_magtheridon_shadow_grasp_AuraScript::HandleDummyApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
			OnEffectRemove += AuraEffectRemoveFn(spell_magtheridon_shadow_grasp_AuraScript::HandleDummyRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
			OnEffectRemove += AuraEffectRemoveFn(spell_magtheridon_shadow_grasp_AuraScript::HandlePeriodicRemove, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
        }
    };

    AuraScript* GetAuraScript() const
    {
        return new spell_magtheridon_shadow_grasp_AuraScript();
    }
};

void AddSC_boss_magtheridon()
{
    new boss_magtheridon();
	new spell_magtheridon_blaze();
	new spell_magtheridon_shadow_grasp();
}

